package com.dy.yunying.biz.service.datacenter.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.R;
import com.dy.yunying.api.dto.AdMaterialDataDTO;
import com.dy.yunying.api.dto.MaterialDataDTO;
import com.dy.yunying.api.entity.ChannelManageDO;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.vo.MaterialDataVO;
import com.dy.yunying.api.vo.XingTuDataVO;
import com.dy.yunying.biz.dao.ads.AdTagRelateMapper;
import com.dy.yunying.biz.dao.datacenter.impl.AdMaterialDataDao;
import com.dy.yunying.biz.dao.datacenter.impl.MaterialDataDao;
import com.dy.yunying.biz.dao.datacenter.impl.MaterialExperienceDataDao;
import com.dy.yunying.biz.dao.manage.ChannelManageDOMapper;
import com.dy.yunying.biz.dao.manage.ParentGameDOMapper;
import com.dy.yunying.biz.service.datacenter.MaterialDataService;
import com.dy.yunying.biz.service.manage.AdRoleUserService;
import com.google.api.client.util.Lists;
import com.pig4cloud.pig.admin.api.feign.RemoteUserService;
import com.pig4cloud.pig.api.entity.AdLandingPage;
import com.pig4cloud.pig.api.entity.AdMaterial;
import com.pig4cloud.pig.api.entity.tag.AdTagRelate;
import com.pig4cloud.pig.api.feign.RemoteAdMaterialService;
import com.pig4cloud.pig.api.feign.RemoteLandingPageService;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.security.util.SecurityUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 素材数据报表Service
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MaterialDataServiceImpl implements MaterialDataService {

	private final static int DEFAULT_QUERY_BATCH = 200;

	private final MaterialDataDao materialDataDao;

	private final AdMaterialDataDao adMaterialDataDao;

	private final AdTagRelateMapper adTagRelateMapper;

	private final RemoteAdMaterialService remoteAdMaterialService;

	private final RemoteLandingPageService remoteLandingPageService;

	private final MaterialExperienceDataDao materialExperienceDataDao;

	// 查询主游戏
	@Autowired
	@Qualifier("parentGameDOMapper")
	private ParentGameDOMapper parentGameMapper;

	// 查询子游戏
	/*private final WanGameDOMapper wanGameDOMapper;*/

	private final RemoteUserService remoteUserService;

	// 查询主子渠道
	private final ChannelManageDOMapper channelManageDOMapper;

	// 查询分包渠道
	/*private final WanGameChannelInfoMapper wanGameChannelInfoMapper;*/

	private final AdRoleUserService roleUserService;



	/**
	 * 查询数据报表总数
	 *
	 * @param material
	 * @return
	 */
	@Override
	public Integer count(MaterialDataVO material) {
		return "1".equals(material.getExperience()) ? materialExperienceDataDao.count(material) : materialDataDao.count(material);
	}

	/**
	 * 查询数据报表列表
	 *
	 * @param material
	 * @param paged
	 * @return
	 */
	@Override
	public List<MaterialDataDTO> list(MaterialDataVO material, boolean paged) {
		final List<MaterialDataDTO> list = "1".equals(material.getExperience()) ? materialExperienceDataDao.list(material, paged) : materialDataDao.list(material, paged);
		this.completeDataList(material, list);
		return list;
	}

	private void completeDataList(MaterialDataVO material, List<MaterialDataDTO> list) {
		final Collection<String> groupBys = material.getGroupBys();

		// 填充素材相关数据
		this.completeMaterialDataList(list, groupBys);

		// 填充落地页信息
		this.completeLandingPageValue(list, groupBys);

		//  填充主渠道信息
		this.completeParentchlNameValue(list, groupBys);
	}

	public R materialData(MaterialDataVO material){
		// 标签数据  根据标签取素材ID
		if (2 == material.getDataType()){
			if (StringUtils.isNotBlank(material.getTagIds())){
				List<String> tagIds = Arrays.asList(material.getTagIds().split(","));
				List<AdTagRelate> adTagRelateList = adTagRelateMapper.selectList(Wrappers.<AdTagRelate>lambdaQuery()
						.select(AdTagRelate::getRelateId).in(AdTagRelate::getTagId, tagIds)
						.eq(AdTagRelate::getType, 1)
						.eq(AdTagRelate::getDeleted, 0));
				if (CollectionUtils.isNotEmpty(adTagRelateList)){
					List<Long> relateIds = adTagRelateList.stream().map(AdTagRelate::getRelateId).collect(Collectors.toList());
					// 取集合出现次数最多的值，返回集合 (取交集)
					List<String> materialIds = this.getMostFrequentValue(relateIds, tagIds.size()).stream().map(String::valueOf).collect(Collectors.toList());
					if (CollectionUtils.isNotEmpty(materialIds)){
						material.setMaterialIds(String.join(",", materialIds));
					}else{
						return R.ok(Lists.newArrayList());
					}
				}else{
					return R.ok(Lists.newArrayList());
				}
			}
		}
		if (1 == material.getPeriod()){
			return R.ok(adMaterialDataDao.materialData(material));
		} else if (4 == material.getPeriod()){
			List<AdMaterialDataDTO> materialDataDTOList = adMaterialDataDao.materialData(material);
			return R.ok(CollectionUtils.isNotEmpty(materialDataDTOList) ? materialDataDTOList.get(0) : null);
		}
		return R.ok(Lists.newArrayList());
	}
	/**
	 * 取集合出现次数最多的值，返回集合 (取交集)
	 * @param list
	 * @return
	 */
	public Set<Long> getMostFrequentValue(List<Long> list, int maxValue) {
		if (list == null || list.isEmpty()) {
			return Collections.emptySet();
		}
		Map<Long, Long> map = list.stream()
				.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
//		Long maxValue = map.values().stream().max(Comparator.naturalOrder()).get();

		return map.entrySet().stream().filter(entry -> entry.getValue() == maxValue)
				.map(Map.Entry::getKey).collect(Collectors.toSet());
	}


	private static <E, K> void batchProcess(Collection<E> collections, int batchSize, Function<E, K> getKey, Consumer<List<K>> process) {
		final List<K> tempList = new ArrayList<>(batchSize);
		for (E e : collections) {
			int size = tempList.size();
			if (size > 0 && size % batchSize == 0) {
				process.accept(tempList);
				tempList.clear();
			}
			K apply = getKey.apply(e);
			if (null != apply) {
				tempList.add(apply);
			}
		}
		if (!collections.isEmpty()) {
			process.accept(tempList);
			tempList.clear();
		}
	}

	private void completeMaterialDataList(List<MaterialDataDTO> list, Collection<String> groupBys) {
		if (!groupBys.contains("materialId")) {
			return;
		}

		// 填充素材信息
		final Map<Long, AdMaterial> materialMapping = new HashMap<>();
		final List<Integer> userIdList = new ArrayList<>();
		final List<Long> pgidList = new ArrayList<>();
		batchProcess(list, DEFAULT_QUERY_BATCH, MaterialDataDTO::getMaterialId, (keys) -> remoteAdMaterialService.getMaterialListByIds(SecurityConstants.FROM_IN, keys).getData().forEach(e -> materialMapping.put(e.getId(), e)));
		if (materialMapping.isEmpty()) {
			return;
		}
		for (MaterialDataDTO data : list) {
			AdMaterial material = materialMapping.get(data.getMaterialId());
			if (null == material) {
				continue;
			}
			data.setMaterialName(material.getName()).setMaterialType(material.getType()).setMaterialFileUrl(material.getFileUrl()).setMaterialCoverUrl(material.getImageUrl());
			data.setCreatorId(material.getCreatorId()).setMakerId(material.getMakerId()).setMaterialWidth(material.getWidth()).setMaterialHeight(material.getHeight());
			data.setPgid(Long.valueOf(material.getMainGameId())).setMakeType(material.getMakeType()).setPgid(Long.valueOf(material.getMainGameId())).setMakeType(material.getMakeType());
			if (null != material.getCreatorId()) {
				userIdList.add(material.getCreatorId());
			}
			if (null != material.getMakerId()) {
				userIdList.add(material.getMakerId());
			}
			if (null != material.getMainGameId()) {
				pgidList.add(Long.valueOf(material.getMainGameId()));
			}
		}

		// 填充创意者与制作者姓名
		final Map<Integer, String> userMapping = new HashMap<>();
		batchProcess(userIdList, DEFAULT_QUERY_BATCH, e -> e, (keys) -> remoteUserService.getUserIdAndNameByIds(SecurityConstants.FROM_IN, keys).getData().forEach(e -> userMapping.put(e.getUserId(), e.getRealName())));
		if (userMapping.isEmpty()) {
			return;
		}
		for (MaterialDataDTO data : list) {
			final String creatorName = userMapping.get(data.getCreatorId());
			final String makerName = userMapping.get(data.getMakerId());
			data.setCreatorName(creatorName).setMakerName(makerName);
		}

		// 填充主游戏名称
		final Map<Long, String> pgameMapping = new HashMap<>();
		batchProcess(pgidList, DEFAULT_QUERY_BATCH, e -> e, (keys) -> {
			final LambdaQueryWrapper<ParentGameDO> pgameQueryWrapper = Wrappers.<ParentGameDO>lambdaQuery().select(ParentGameDO::getId, ParentGameDO::getGname).in(ParentGameDO::getId, keys);
			parentGameMapper.selectList(pgameQueryWrapper).forEach(e -> pgameMapping.put(e.getId(), e.getGname()));
		});
		
		Set<Long> set = remoteAdMaterialService.getPreparePushMaterial(SecurityConstants.FROM_IN, String.valueOf(SecurityUtils.getUser().getId())).getData();
		
		for (MaterialDataDTO data : list) {
			data.setPgname(pgameMapping.get(data.getPgid()));
			if(set.contains(data.getMaterialId())){
				data.setInBox(1);
			}
		}

	}

	private void completeLandingPageValue(List<MaterialDataDTO> list, Collection<String> groupBys) {
		if (!groupBys.contains("landingPageId")) {
			return;
		}

		final Map<String, AdLandingPage> landingPageMapping = new HashMap<>();
		batchProcess(list, DEFAULT_QUERY_BATCH, MaterialDataDTO::getLandingPageId, (keys) -> remoteLandingPageService.getLandingPageListByIds(SecurityConstants.FROM_IN, keys).getData().forEach(e -> landingPageMapping.put(e.getPageId(), e)));

		if (landingPageMapping.isEmpty()) {
			return;
		}
		for (MaterialDataDTO data : list) {
			final AdLandingPage landingPage = landingPageMapping.get(data.getLandingPageId());
			if (null == landingPage) {
				continue;
			}
			final Integer platformId = landingPage.getPlatformId();
			final String pageName = landingPage.getPageName();
			final String pageType = landingPage.getPageType();
			final String pageUrl = landingPage.getPageUrl();
			final String pageTypeStr;
			if (null == platformId) {
				pageTypeStr = "-";
			} else if (Integer.parseInt(PlatformTypeEnum.GDT.getValue()) == platformId) {
				pageTypeStr = "蹊径落地页";
			} else if ("TT_GROUP".equals(pageType)) {
				pageTypeStr = "程序化落地页";
			} else if ("TT_ORANGE".equals(pageType)) {
				pageTypeStr = "橙子落地页";
			} else {
				pageTypeStr = "-";
			}
			data.setLandingPageName(pageName).setLandingPageType(pageType).setLandingPageTypeStr(pageTypeStr).setLandingPageUrl(pageUrl);
		}
	}

	private void completeParentchlNameValue(List<MaterialDataDTO> list, Collection<String> groupBys) {
		if (!groupBys.contains("parentchl")) {
			return;
		}

		final Map<String, String> parentchlMapping = new HashMap<>();
		batchProcess(list, DEFAULT_QUERY_BATCH, MaterialDataDTO::getParentchl, (keys) -> {
			final LambdaQueryWrapper<ChannelManageDO> queryWrapper = Wrappers.<ChannelManageDO>lambdaQuery().select(ChannelManageDO::getChncode, ChannelManageDO::getChnname).in(ChannelManageDO::getChncode, keys).eq(ChannelManageDO::getPid, NumberUtils.INTEGER_ZERO);
			channelManageDOMapper.selectList(queryWrapper).forEach(e -> parentchlMapping.put(e.getChncode(), e.getChnname()));
		});

		if (parentchlMapping.isEmpty()) {
			return;
		}
		for (MaterialDataDTO data : list) {
			final String parentCodeName = parentchlMapping.get(data.getParentchl());
			data.setParentchlName(parentCodeName);
		}
	}




}
